add git-remote-p2p-annex
authorJoey Hess <joeyh@joeyh.name>
Wed, 30 Jul 2025 19:25:17 +0000 (15:25 -0400)
committerJoey Hess <joeyh@joeyh.name>
Wed, 30 Jul 2025 19:25:56 +0000 (15:25 -0400)
Added git-remote-p2p-annex, which allows git pull and push to P2P networks
provided by external commands.

This is a refactor of git-remote-tor-annex, and should just work. Except
possibly for quirks with the address parsing. I've checked that the address
parsing basically works.

One thing I don't understand is why git-remote-tor-annex removes "/*" from
the end of the address. The git history does not provide any hints. So I
didn't make git-remote-p2p-annex do the same. Maybe that is needed in some
situation? But, a P2P address could contain "/", so removing it would be a
problem. I can't see anything in gitremote-helpers(7) about why the url
might get such a thing added to the end of it. My guess is that is not
needed for tor either (but does no harm there since onion addresses never
contain "/").

At this point, the implementation of generic P2P transports needs only
remotedaemon support.

.gitignore
Build/Standalone.hs
CHANGELOG
CmdLine/GitRemoteP2PAnnex.hs [new file with mode: 0644]
CmdLine/GitRemoteTorAnnex.hs
CmdLine/Multicall.hs
Makefile
git-annex.cabal
git-annex.hs
standalone/linux/skel/runshell

index a6daf2efd642bbe31bc791c9b4f885af1589d0db..3c4a7a277cff7737496b93e6e367fd5767d7360e 100644 (file)
@@ -14,6 +14,7 @@ Build/MakeMans
 git-annex
 git-annex-shell
 git-remote-annex
+git-remote-p2p-annex
 git-remote-tor-annex
 man
 doc/.ikiwiki
index 2c0c8d1b55bcf71e5fcca25a57bdf9d1f49df6be..b9a683fb0bbf8556a7ae2ce6cff1735751646605 100644 (file)
@@ -222,6 +222,7 @@ installGitAnnex topdir = go (topdir </> literalOsPath "bin")
                unlessM (boolSystem "strip" [File (fromOsPath (bindir </> literalOsPath "git-annex"))]) $
                        error "strip failed"
                createSymbolicLink "git-annex" (fromOsPath (bindir </> literalOsPath "git-annex-shell"))
+               createSymbolicLink "git-annex" (fromOsPath (bindir </> literalOsPath "git-remote-p2p-annex"))
                createSymbolicLink "git-annex" (fromOsPath (bindir </> literalOsPath "git-remote-tor-annex"))
                createSymbolicLink "git-annex" (fromOsPath (bindir </> literalOsPath "git-remote-annex"))
 
index cb1223ee0d271715ba7e06e720f4d67ebe175200..29e18503abd813bdec84423fbe364326c8873cc5 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,8 @@ git-annex (10.20250722) UNRELEASED; urgency=medium
 
   * p2p: Added --enable option, which can be used to enable P2P networks
     provided by external commands git-annex-p2p-<netname>
+  * Added git-remote-p2p-annex, which allows git pull and push to
+    P2P networks provided by external commands.
 
  -- Joey Hess <id@joeyh.name>  Wed, 30 Jul 2025 13:45:42 -0400
 
diff --git a/CmdLine/GitRemoteP2PAnnex.hs b/CmdLine/GitRemoteP2PAnnex.hs
new file mode 100644 (file)
index 0000000..fcc77e1
--- /dev/null
@@ -0,0 +1,62 @@
+{- git-remote-p2p-annex program
+ -
+ - Copyright 2016-2025 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU AGPL version 3 or higher.
+ -}
+
+module CmdLine.GitRemoteP2PAnnex where
+
+import Common
+import qualified Annex
+import qualified Git.CurrentRepo
+import P2P.Protocol
+import P2P.IO
+import Utility.AuthToken
+import Annex.UUID
+import P2P.Address
+import P2P.Auth
+import Annex.Action
+
+run :: [String] -> IO ()
+run = runner mkaddress
+  where
+       mkaddress address = 
+               fromMaybe (error $ "unable to parse address: " ++ address) $
+                       unformatP2PAddress (p2pAnnexScheme ++ ":" ++ address)
+
+runner :: (String -> P2PAddress) -> [String] -> IO ()
+runner mkaddress (_remotename:saddress:[]) = forever $
+       getLine >>= \case
+               "capabilities" -> putStrLn "connect" >> ready
+               "connect git-upload-pack" -> go UploadPack
+               "connect git-receive-pack" -> go ReceivePack
+               l -> giveup $ "gitremote-helpers protocol error at " ++ show l
+  where
+       address = mkaddress saddress
+       go service = do
+               ready
+               connectService address service >>= \case
+                       Right exitcode -> exitWith exitcode
+                       Left e -> giveup $ describeProtoFailure e
+       ready = do
+               putStrLn ""
+               hFlush stdout   
+runner _ (_remotename:[]) = giveup "remote address not configured"
+runner _ _ = giveup "expected remote name and address parameters"
+
+connectService :: P2PAddress -> Service -> IO (Either ProtoFailure ExitCode)
+connectService address service = do
+       state <- Annex.new =<< Git.CurrentRepo.get
+       Annex.eval state $ do
+               authtoken <- fromMaybe nullAuthToken
+                       <$> loadP2PRemoteAuthToken address
+               myuuid <- getUUID
+               g <- Annex.gitRepo
+               conn <- liftIO $ connectPeer (Just g) address
+               runst <- liftIO $ mkRunState Client
+               r <- liftIO $ runNetProto runst conn $ auth myuuid authtoken noop >>= \case
+                       Just _theiruuid -> connect service stdin stdout
+                       Nothing -> giveup $ "authentication failed, perhaps you need to set " ++ p2pAuthTokenEnv
+               quiesce False
+               return r
index 476eab0231388e51d3483f4755ffb04e09bc3739..8ec9326d14f94122c640707d8e66ecdf62d722b6 100644 (file)
@@ -8,40 +8,19 @@
 module CmdLine.GitRemoteTorAnnex where
 
 import Common
-import qualified Annex
-import qualified Git.CurrentRepo
-import P2P.Protocol
-import P2P.IO
 import Utility.Tor
-import Utility.AuthToken
-import Annex.UUID
 import P2P.Address
-import P2P.Auth
-import Annex.Action
+import CmdLine.GitRemoteP2PAnnex (runner)
 
 run :: [String] -> IO ()
-run (_remotename:address:[]) = forever $
-       getLine >>= \case
-               "capabilities" -> putStrLn "connect" >> ready
-               "connect git-upload-pack" -> go UploadPack
-               "connect git-receive-pack" -> go ReceivePack
-               l -> giveup $ "gitremote-helpers protocol error at " ++ show l
+run = runner mkaddress
   where
-       (onionaddress, onionport)
-               | '/' `elem` address = parseAddressPort $
-                       reverse $ takeWhile (/= '/') $ reverse address
-               | otherwise = parseAddressPort address
-       go service = do
-               ready
-               connectService onionaddress onionport service >>= \case
-                       Right exitcode -> exitWith exitcode
-                       Left e -> giveup $ describeProtoFailure e
-       ready = do
-               putStrLn ""
-               hFlush stdout
-               
-run (_remotename:[]) = giveup "remote address not configured"
-run _ = giveup "expected remote name and address parameters"
+       mkaddress address =
+               let (onionaddress, onionport)
+                       | '/' `elem` address = parseAddressPort $
+                               reverse $ takeWhile (/= '/') $ reverse address
+                       | otherwise = parseAddressPort address
+               in TorAnnex onionaddress onionport
 
 parseAddressPort :: String -> (OnionAddress, OnionPort)
 parseAddressPort s = 
@@ -49,19 +28,3 @@ parseAddressPort s =
        in case readish sp of
                Nothing -> giveup "onion address must include port number"
                Just p -> (OnionAddress a, p)
-
-connectService :: OnionAddress -> OnionPort -> Service -> IO (Either ProtoFailure ExitCode)
-connectService address port service = do
-       state <- Annex.new =<< Git.CurrentRepo.get
-       Annex.eval state $ do
-               authtoken <- fromMaybe nullAuthToken
-                       <$> loadP2PRemoteAuthToken (TorAnnex address port)
-               myuuid <- getUUID
-               g <- Annex.gitRepo
-               conn <- liftIO $ connectPeer (Just g) (TorAnnex address port)
-               runst <- liftIO $ mkRunState Client
-               r <- liftIO $ runNetProto runst conn $ auth myuuid authtoken noop >>= \case
-                       Just _theiruuid -> connect service stdin stdout
-                       Nothing -> giveup $ "authentication failed, perhaps you need to set " ++ p2pAuthTokenEnv
-               quiesce False
-               return r
index fa25836d3756b87f48c28d0411a6003913a4a895..566cd6d98888bf48c4999ba71fb628157dd8265c 100644 (file)
@@ -1,6 +1,6 @@
 {- git-annex multicall binary
  -
- - Copyright 2024 Joey Hess <id@joeyh.name>
+ - Copyright 2024-2025 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -17,12 +17,14 @@ import qualified Data.Map as M
 data OtherMultiCallCommand
        = GitAnnexShell
        | GitRemoteAnnex
+       | GitRemoteP2PAnnex
        | GitRemoteTorAnnex
 
 otherMulticallCommands :: M.Map String OtherMultiCallCommand
 otherMulticallCommands = M.fromList
        [ ("git-annex-shell", GitAnnexShell)
        , ("git-remote-annex", GitRemoteAnnex)
+       , ("git-remote-p2p-annex", GitRemoteP2PAnnex)
        , ("git-remote-tor-annex", GitRemoteTorAnnex)
        ]
 
index e161d79bddee7fde4a8064a7eccf0ad15ef7b10c..e1ddb9d510aaa1e75b78248c962e45c562398017 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-all=git-annex git-annex-shell git-remote-annex git-remote-tor-annex mans docs
+all=git-annex git-annex-shell git-remote-annex git-remote-p2p-annex git-remote-tor-annex mans docs
 
 # set to "./Setup" if you lack a cabal program. Or can be set to "stack"
 BUILDER?=cabal
@@ -74,6 +74,9 @@ git-annex-shell: git-annex
 git-remote-annex: git-annex
        @ln -sf git-annex git-remote-annex
 
+git-remote-p2p-annex: git-annex
+       @ln -sf git-annex git-remote-p2p-annex
+
 git-remote-tor-annex: git-annex
        @ln -sf git-annex git-remote-tor-annex
 
@@ -93,6 +96,7 @@ install-bins: build
        ln -sf git-annex $(DESTDIR)$(PREFIX)/bin/git-annex-shell
        ln -sf git-annex $(DESTDIR)$(PREFIX)/bin/git-remote-annex
        ln -sf git-annex $(DESTDIR)$(PREFIX)/bin/git-remote-tor-annex
+       ln -sf git-annex $(DESTDIR)$(PREFIX)/bin/git-remote-p2p-annex
 
 install-desktop: build Build/InstallDesktopFile
        ./Build/InstallDesktopFile $(PREFIX)/bin/git-annex || true
index ac9941b90297a12d3ab0b57c8bf775e4e1e478d6..199e97e6927eabe9e6f5b63cc4bffa2310d47cb5 100644 (file)
@@ -649,6 +649,7 @@ Executable git-annex
     CmdLine.AnnexSetter
     CmdLine.Multicall
     CmdLine.GitRemoteAnnex
+    CmdLine.GitRemoteP2PAnnex
     CmdLine.GitRemoteTorAnnex
     CmdLine.Option
     CmdLine.Seek
index 8f98d7726545966f72d64ebe6792c51675d6be20..5d1b1cf674a8dd7ec9bc9ca0b22136a54e09a8cc 100644 (file)
@@ -16,6 +16,7 @@ import CmdLine.Multicall
 import qualified CmdLine.GitAnnex
 import qualified CmdLine.GitAnnexShell
 import qualified CmdLine.GitRemoteAnnex
+import qualified CmdLine.GitRemoteP2PAnnex
 import qualified CmdLine.GitRemoteTorAnnex
 import qualified Test
 import qualified Benchmark
@@ -39,6 +40,7 @@ main = sanitizeTopLevelExceptionMessages $ withSocketsDo $ do
        run ps n = case M.lookup (takeFileName n) otherMulticallCommands of
                Just GitAnnexShell -> CmdLine.GitAnnexShell.run ps
                Just GitRemoteAnnex -> CmdLine.GitRemoteAnnex.run ps
+               Just GitRemoteP2PAnnex -> CmdLine.GitRemoteP2PAnnex.run ps
                Just GitRemoteTorAnnex -> CmdLine.GitRemoteTorAnnex.run ps
                Nothing -> CmdLine.GitAnnex.run
                        Test.optParser
index 1360d31fe8b24ef3c181f194bebc26900fb001c3..63cc1ab9ead97974e553595fd363b9a137a09deb 100755 (executable)
@@ -206,7 +206,7 @@ case "$os" in
                        # The bundled git does not work well on sdcard, so delete
                        # it and use termux's git which works better.
                        cd "$base"
-                       find . | grep git | grep -v git-annex | grep -v git-remote-annex | grep -v git-remote-tor-annex | grep -v git-remote-gcrypt | xargs rm -rf
+                       find . | grep git | grep -v git-annex | grep -v git-remote-annex | grep -v git-remote-p2p-annex | grep -v git-remote-tor-annex | grep -v git-remote-gcrypt | xargs rm -rf
                        # Use termux's uname, which knows it's on android,
                        # not the bundled one.
                        rm -f bin/uname